package com.zlyx.easy.netty.server.core;

import java.lang.reflect.ParameterizedType;
import java.util.Arrays;

import com.alibaba.fastjson.JSONObject;
import com.zlyx.easy.core.handler.IHandler;
import com.zlyx.easy.core.tool.Hex;
import com.zlyx.easy.core.utils.ByteUtils;
import com.zlyx.easy.core.utils.JsonUtils;
import com.zlyx.easy.core.utils.LogUtils;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
 
/**
 * 
 * @Auth 赵光
 * @Describle 抽象netty服务端
 * @2019年1月25日 下午2:45:23
 */
@Sharable
public abstract class AbstractNettyServer<T> extends ChannelInboundHandlerAdapter implements IHandler<T>{

	private Class<T> tClass = getTClass(this.getClass());

	protected ChannelHandlerContext ctx;
	/**
	 * 读数据
	 */
    @SuppressWarnings("unchecked")
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            byte[] bytes = (byte[])msg;
			T data = null;
			if (bytes != null) {
				this.ctx = ctx;
				if (Hex.class == tClass) {
					data = (T) Hex.newHex(ByteUtils.bytesToHexString(bytes));
				} else if (byte[].class == tClass) {
					data = (T) bytes;
				} else if (JSONObject.class == tClass) {
					data = (T) JsonUtils.parse(bytes);
				} else {
					data = (T) new String(bytes);
				}
				write(doHandle(data));
			}
        } catch(Exception e){
        	e.printStackTrace();
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
    
    public void write(T msg) throws Exception {
		if (msg != null) {
			if (Hex.class == tClass) {
				this.writeBytes(ByteUtils.hexStringToByte(((Hex) msg).getHex()));
			} else if (byte[].class == tClass) {
				this.writeBytes((byte[]) msg);
			} else if (JSONObject.class == tClass) {
				this.writeBytes(((JSONObject) msg).toString().getBytes());
			} else if (String.class == tClass) {
				this.writeBytes(((String) msg).getBytes());
			} else if (Object.class == tClass) {
				this.writeBytes(msg.toString().getBytes());
			} else {
				this.writeBytes(((String) msg).getBytes());
			}
		}
	}
    
    public void writeBytes(byte[] bytes) throws Exception {
		if (bytes != null) {
			LogUtils.info(this.getClass(),  Arrays.toString(bytes));
			Channel channel = ctx.channel();
            channel.writeAndFlush(bytes);
		}
	}
 
    /**
     * 没有事件活跃时,主动关闭通道
     */
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                ctx.close();
            }
        }
    }
 
    /**
     * 异常处理
     */
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {
    	e.printStackTrace();
        ctx.close();
    }
    
    /**
	 * 处理消息
	 * @return
     * @throws Exception 
	 */
    @Override
	public abstract T doHandle(T msg) throws Exception;
    
    @SuppressWarnings("unchecked")
	public Class<T> getTClass(Class<?> tClass) {
		if(tClass.getGenericSuperclass().getTypeName().contains("<")) {	
			return (Class<T>) ((ParameterizedType) tClass.getGenericSuperclass()).getActualTypeArguments()[0];
		}else if(tClass != Object.class){
			return getTClass(tClass.getSuperclass());
     	}
		return null;
	}
	
	/**
	 * 代码控制是否开启(优先级大于@NettyServer注解)
	 * @return
	 */
	public boolean isOpen() {
		return true;
	}
}
